#include "service.h"
#include <cassert>

namespace cores
{
    namespace services
    {
        ServiceManager *ServiceManager::globalInstance{nullptr};

        BaseService::BaseService(const string &serviceName) : _serviceName(serviceName)
        {
            ServiceManager::AddService(this);
        }

        BaseService::~BaseService()
        {
            ServiceManager::RemoveService(this);
            stop();
        }

        void BaseService::init()
        {}

        void BaseService::start()
        {}

        void BaseService::stop()
        {
            if (_running)
                _running = false;
        }

        bool BaseService::isRunning() const
        {
            return _running;
        }

        string BaseService::name() const
        {
            return _serviceName;
        }

        ServiceManager::ServiceManager()
        {
            if (ServiceManager::globalInstance == nullptr)
                ServiceManager::globalInstance = this;
        }

        ServiceManager::~ServiceManager()
        {
            if (ServiceManager::globalInstance == this)
                ServiceManager::globalInstance = nullptr;
        }

        BaseService *ServiceManager::Instance(const string &serviceName)
        {
            assert(ServiceManager::globalInstance);
            return ServiceManager::globalInstance->getBaseServiceInstance(serviceName);
        }

        BaseService *ServiceManager::getBaseServiceInstance(const string &serviceName)
        {
            if (_services.count(serviceName) == 0)
                return nullptr;

            return _services[serviceName];
        }

        void ServiceManager::InitServices()
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->initServices();
        }

        void ServiceManager::initServices()
        {
            for (auto &service : _services)
            {
                service.second->init();
            }
        }

        void ServiceManager::AddService(BaseService *servicePtr)
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->addService(servicePtr);
        }

        void ServiceManager::addService(BaseService *servicePtr)
        {
            if (_services.count(servicePtr->name()) == 0)
                _services[servicePtr->name()] = servicePtr;
        }

        void ServiceManager::RemoveService(BaseService *servicePtr)
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->removeService(servicePtr);
        }

        void ServiceManager::removeService(BaseService *servicePtr)
        {
            if (_services.count(servicePtr->name()) == 0 ||
                _services[servicePtr->name()] != servicePtr)
                return;

            _services.erase(servicePtr->name());
        }

        void ServiceManager::StartAllServices()
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->startAllServices();
        }

        void ServiceManager::startAllServices()
        {
            for (auto &service : _services)
            {
                service.second->start();
            }
        }

        void ServiceManager::StartService(const string &serviceName)
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->startService(serviceName);
        }

        void ServiceManager::startService(const string &serviceName)
        {
            if (_services.count(serviceName) > 0)
                _services[serviceName]->start();
        }

        bool ServiceManager::ServiceIsRunning(const string &serviceName)
        {
            assert(ServiceManager::globalInstance);
            return ServiceManager::globalInstance->serviceIsRunning(serviceName);
        }

        bool ServiceManager::serviceIsRunning(const string &serviceName)
        {
            return _services.count(serviceName) == 0 ? false : _services[serviceName]->isRunning();
        }

        void ServiceManager::StopAllServices()
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->stopAllServices();
        }

        void ServiceManager::stopAllServices()
        {
            for (auto &service : _services)
            {
                service.second->stop();
            }
        }

        void ServiceManager::StopService(const string &serviceName)
        {
            assert(ServiceManager::globalInstance);
            ServiceManager::globalInstance->stopService(serviceName);
        }

        void ServiceManager::stopService(const string &serviceName)
        {
            if (_services.count(serviceName) > 0)
                _services[serviceName]->stop();
        }

        vector<string> ServiceManager::GetServieNames()
        {
            assert(ServiceManager::globalInstance);
            return ServiceManager::globalInstance->getServiceNames();
        }

        vector<string> ServiceManager::getServiceNames() const
        {
            vector<string> result;
            if (_services.size() > 0)
            {
                result.reserve(_services.size());
                for (auto &service : _services)
                    result.push_back(service.second->name());
            }
            return result;
        }
    }
}